﻿using System;
using System.Collections.Generic;
using System.Linq;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace WorldOnFire
{
    public abstract class ABCMenu : ABCState
    {
        protected static Game s_Game;

        public static void SetGame(Game _Game)
        { s_Game = _Game; }

        public struct tExpandableOption
        {
            public string[] strOptionTitles;

            public int nOptionCount;
            public int nSelectedIndex;
        }

        protected SpriteFont m_Font;

        // TODO: CHANGE THE FUCKING ACCESS
        protected string[] m_strOptionTitles;
        public int m_nOptionCount;

        public tExpandableOption[] m_ExpandableOptions;
        protected int[] m_nExpandableOptionIndices;
        public int m_nExpandableOptionCount;

        private float m_fScrollIncrementTimer;
        private float m_fScrollTimer;

        protected int m_nSelectedIndex;
        protected bool m_bSelectionExpanded;
        protected bool m_bSelectionActive;

        private const float OPTION_SIZE = 50.0f;
        private const float EXPANDABLE_OPTION_SIZE = 40.0f;
        private const float SCROLL_DELAY_MAX = 0.5f;
        private const float SCROLL_DELAY_MIN = 0.15f;

        public ABCMenu()
        {

        }

        public override void Initialize()
        {
            // TODO: FFFFFFFUUUU GRAPHICS INITIALIZE
            m_Font = s_ContentManager.Load<SpriteFont>("Miscellaneous/Calibri");
        }

        public override void Input(float _fDeltaTime)
        {
            // TODO: If ESC is pressed
            if(SInputManager.IsKeyPressed(Keys.Escape) == true)
            {
                // If the selected option is active
                if (m_bSelectionActive == true)
                {
                    // De-activate it
                    m_bSelectionActive = false;
                }
                // If the selected option is not active
                else
                {
                    // Un-expand the option (it doesn't matter whether or not it's expanded)
                    m_bSelectionExpanded = false;
                }
            }

            // If the selected option is active
            if (m_bSelectionActive == true)
            {
                // Bail out; the derived menu should handle up/down input
                return;
            }

            // TODO: If either the up or down key is pressed
            if (SInputManager.IsKeyDown(Keys.Up) == true ||
                SInputManager.IsKeyDown(Keys.Down) == true)
            {
                // If the scroll timer has gone long enough
                if (m_fScrollIncrementTimer > MathHelper.Lerp(SCROLL_DELAY_MAX, SCROLL_DELAY_MIN, MathHelper.Clamp(m_fScrollTimer, 0.0f, 1.0f)))
                {
                    // Reset the timer and keep going
                    m_fScrollIncrementTimer = 0.0f;
                }
                else
                {
                    // Bail out
                    return;
                }

                // If the selected option is expanded
                if (m_bSelectionExpanded == true)
                {
                    // Find which expandable option the selected index correlates to
                    for (int iExpandable = 0;
                        iExpandable < m_nExpandableOptionCount; ++iExpandable)
                    {
                        // If the current expandable option is the correct one
                        if (m_nExpandableOptionIndices[iExpandable] == m_nSelectedIndex)
                        {
                            //////////////////////////////////////////////////////////
                            // The expandable option handles input
                            //////////////////////////////////////////////////////////

                            // TODO: If the up key was pressed
                            if (SInputManager.IsKeyDown(Keys.Up) == true)
                            {
                                // If the selected item is the top of the menu
                                if (--m_ExpandableOptions[iExpandable].nSelectedIndex < 0)
                                {
                                    // Loop around to the bottom of the menu
                                    m_ExpandableOptions[iExpandable].nSelectedIndex
                                        = m_ExpandableOptions[iExpandable].nOptionCount - 1;
                                }
                            }
                            // TODO: If the down key was pressed
                            if (SInputManager.IsKeyDown(Keys.Down) == true)
                            {
                                // If the selected item is the bottom of the menu
                                if (++m_ExpandableOptions[iExpandable].nSelectedIndex
                                    == m_ExpandableOptions[iExpandable].nOptionCount)
                                {
                                    // Loop around to the top of the menu
                                    m_ExpandableOptions[iExpandable].nSelectedIndex = 0;
                                }
                            }

                            // Bail out
                            break;
                        }
                    }
                }
                // If there is no expanded menu option
                else
                {
                    //////////////////////////////////////////////////////////
                    // The menu handles input
                    //////////////////////////////////////////////////////////

                    // TODO: If the up key was pressed
#if XBOX
                    if (SInputManager.GetLeftThumbStick().Y > 0.5f)
#else
                    if (SInputManager.IsKeyDown(Keys.Up) == true)
#endif
                    {
                        // If the selected item is the top of the menu
                        if (--m_nSelectedIndex < 0)
                        {
                            // Loop around to the bottom of the menu
                            m_nSelectedIndex = m_nOptionCount - 1;
                        }
                    }
                    // TODO: If the down key was pressed
                    if (SInputManager.IsKeyDown(Keys.Down) == true)
                    {
                        // If the selected item is the bottom of the menu
                        if (++m_nSelectedIndex == m_nOptionCount)
                        {
                            // Loop around to the top of the menu
                            m_nSelectedIndex = 0;
                        }
                    }
                }
            }
            // If neither up nor down are being pressed
            else
            {
                // Reset the scroll timers
                m_fScrollTimer = 0.0f;
                m_fScrollIncrementTimer = SCROLL_DELAY_MAX;
            }
        }

        public override void Update( float _fDeltaTime )
        {
            // Update the input timer
            m_fScrollTimer += _fDeltaTime;
            m_fScrollIncrementTimer += _fDeltaTime;
        }

        public override void Render()
        {
            // TODO: Draw background

            ////////////////////////////////////////////
            // Determine the offset for expanded options
            ////////////////////////////////////////////

            // TODO: FOR CHRIST'S SAKE
            // Initilize the index to the index of the last item
            int nExpandedOptionIndex = m_nOptionCount - 1;
            int nOtherExpandableOptionIndex = 0;

            // The number of options in the expanded option
            int nExpandedOptions = 0;

             // If the selected option is expanded
            if (m_bSelectionExpanded == true)
            {
                 // Find which expandable option the selected index correlates to
                for (int iExpandable = 0;
                    iExpandable < m_nExpandableOptionCount; ++iExpandable)
                {
                    // If the current expandable option is the correct one
                    if (m_nExpandableOptionIndices[iExpandable] == m_nSelectedIndex)
                    {

                        // Set the number of expanded options
                        nExpandedOptionIndex = m_nSelectedIndex;
                        nOtherExpandableOptionIndex = iExpandable;
                        nExpandedOptions = m_ExpandableOptions[iExpandable].nOptionCount;
                    
                        // Bail out
                        break;
                    }
                }
            }

            // Begin drawing
            s_SpriteBatch.Begin();

            Vector2 vSelectionPosition = new Vector2(s_vScreenCenter.X - 100.0f, 100.0f + OPTION_SIZE * m_nSelectedIndex);
            if( m_bSelectionExpanded == true )
            {
                vSelectionPosition.Y += EXPANDABLE_OPTION_SIZE * (1 + m_ExpandableOptions[nOtherExpandableOptionIndex].nSelectedIndex);
            }
            s_SpriteBatch.DrawString(
                m_Font,
                "-->",
                vSelectionPosition,
                Color.White,
                0.0f,
                0.5f * m_Font.MeasureString("-->"),
                new Vector2(2.0f, 1.5f),
                SpriteEffects.None,
                0.0f);

            // For each option through the expanded option
            for (int iOption = 0; iOption <= nExpandedOptionIndex; ++iOption)
            {
                // TODO: Draw each option
                // Offset on Y (m_nOptionSize * iOption)
                s_SpriteBatch.DrawString(
                    m_Font, 
                    m_strOptionTitles[iOption], 
                    new Vector2(s_vScreenCenter.X, 100.0f + OPTION_SIZE * iOption), 
                    Color.White,
                    0.0f,
                    0.5f * m_Font.MeasureString(m_strOptionTitles[iOption]),
                    new Vector2(2.0f, 1.5f),
                    SpriteEffects.None,
                    0.0f );
            }

            // For each expanded option
            for (int iOption = 0; iOption < nExpandedOptions; ++iOption)
            {
                // TODO: Draw each option
                // Offset on Y (m_nOptionSize * (iOption + nExpandedOptionIndex))
                Vector2 vOptionPosition = new Vector2(
                    s_vScreenCenter.X, 
                    100.0f +
                    OPTION_SIZE * nExpandedOptionIndex + 
                    EXPANDABLE_OPTION_SIZE * (iOption + 1));

                s_SpriteBatch.DrawString(
                    m_Font,
                    m_ExpandableOptions[nOtherExpandableOptionIndex].strOptionTitles[iOption],
                    vOptionPosition,
                    Color.White,
                    0.0f,
                    0.5f * m_Font.MeasureString(m_ExpandableOptions[nOtherExpandableOptionIndex].strOptionTitles[iOption]),
                    new Vector2(1.5f, 1.0f),
                    SpriteEffects.None,
                    0.0f);
            }

            // For each option after the expanded options
            for (int iOption = nExpandedOptionIndex + 1; iOption < m_nOptionCount; ++iOption)
            {
                // TODO: Draw each option
                // Offset on Y (m_nOptionSize * (iOption + nExpandedOptions))
                Vector2 vOptionPosition = new Vector2(
                    s_vScreenCenter.X,
                    100.0f +
                    OPTION_SIZE * iOption +
                    EXPANDABLE_OPTION_SIZE * (m_ExpandableOptions[nOtherExpandableOptionIndex].nOptionCount));
                   // OPTION_SIZE * iOption);

                s_SpriteBatch.DrawString(
                    m_Font,
                    m_strOptionTitles[iOption],
                    vOptionPosition,
                    Color.White,
                    0.0f,
                    0.5f * m_Font.MeasureString(m_strOptionTitles[iOption]),
                    new Vector2(2.0f, 1.5f),
                    SpriteEffects.None,
                    0.0f);
            }

            // Finish drawing
            s_SpriteBatch.End();
        }
    }
}
